class Inflex {
  url = `http://${window.location.hostname}:8086/query?pretty=false&epoch=ms&db=tw2_database&q=`

  execute(sql) {
    //pretty=true&
    let url = this.url + sql.replace(/[\s\n]+/g, ' ');
    console.log(url)
    return fetch(url).then(v => v.json())
    // 'query?pretty=true&db=mydb&q=SELECT%20value%20FROM%20cpu_load_short'
  }
}

function calculate(expression, vars) { // 使用 new Function 构造器创建一个函数
  return new Function(...Object.keys(vars), `return ${expression};`)(...Object.values(vars));
}

Array.prototype.sum = function () {
  return this.reduce((a, b) => a + b, 0)
}
let in2out = v => v;

function xnum(v) {
  return Number(v.split(':')[0])
}

function isNumInRanges(ranges) {
  t = function (v) {
    return ranges.some(range => v >= range[0] && v <= range[1]);
  }
  return t
}

class Params {
  constructor(id, name, bits, unit, trans, show, check, rawfmt) {
    this.id = id
    this.n = name
    this.bits = bits
    this.unit = unit
    this.V = trans || (v => v)
    this.D = show || (v => v)
    this.C = check || (v => true)
    this.R = rawfmt
  }
}

class PKG {
  // vals  ： 数据库查出来的
  // keys : 数据库里的 key
  // params : 参数解析方案
  constructor(params, keys, vals) {
    this.par = params
    this.input = {}
    this.raw = {}
    this.time = vals[0];
    keys.forEach((k, i) => {
      if (k.includes('time')) return;
      let p = this.par[k];
//       this.input[k] =  p.cali(p.input(vals[i]));
      this.raw[k] = vals[i]
    })
    this.val = {}
  }

  V(name) {
    // 转换物理量
    if (this.val[name]) return this.val[name]
    let p = this.par[name];
    return this.val[name] = p.V(this.raw[name], this.raw)
  }

  R(name) {
    // 用于源码显示
    if (this.raw[name] === null || this.raw[name] === undefined) this.raw[name] = '';
    let p = this.par[name];
    if (p.R) return p.R(this.raw)
    if (p.bits % 4 || p.bits < 8) return '0b' + this.raw[name].toString(2).padStart(p.bits, '0');
    return '0x' + (this.raw[name] >= 0 ? this.raw[name] : '').toString(16).padStart(p.bits / 4, '0').toUpperCase();
  }

  D(name) {
    let p = this.par[name]
    let v = this.V(name);
    return p.D(v);
  }

  td(name) {
    let p = this.par[name]
    let v = this.V(name);
    let st = p.C(v) ? '' : 'class="E"'
    return `<td title="${v}" ${st}>${this.D(name)}${p.Unit || ''}  <kbd>${this.R(name)}</kbd></td>`
  }

  tr(names) {
    let tmp = names.map(name => this.td(name)).join('')
    return `<tr><th>${U2T(this.time)}</th>${tmp}</tr>`
  }

  grid_item(name) {
    let p = this.par[name]
    let v = this.V(name);
    let st = p.C(v) ? '' : 'E'
    return `<div class="grid-inner ${st}" >
      <b>${p.n}</b>
      <i>${p.id}</i>
      <v>${this.D(name)}${p.Unit || ''}</v>
      <kbd>${this.R(name)}</kbd></div>`
  }

  grid(names) {
    let tmp = names.map(name => this.grid_item(name)).join('')
    return `<div class="grid-outer">${tmp}</div>`
  }
}

U2T = (ms) => new Date(ms).toISOString()

class PKGS {
  constructor(params) {
    this.keys = []
    this.par = {}
    this.values = [] // 初始化values数组
    params.forEach(p => {
      this.keys.push(p.id)
      this.par[p.id] = p
    })
  }

  data(name) {
    let meta = this.par[name];
    return {
      info: this.par[name],
      name: meta.n,
      // type: 'scatterGL',
      type: 'scatter',
      // type: 'line3D',
      // type: 'line',
      large: true,
      symbolSize: 3, symbol: 'rect',
      data: this.values.map(v => [v.time, v.V(name)])
    }
  }

  th(name) {
    let p = this.par[name]
    return `<th>${p.id}/${p.n}${p.unit ? (' ' + p.unit) : ''}</th>`;
  }

  thead(names) {
    return `<tr><th>时间</th>${names.map(v => this.th(v)).join('')}</tr>`;
  }

  dataset(data) {
    let d = data.results[0].series
    this.values = [];
    if (d) {
      d = d[0];
      let keys = d.columns.map(v => v.replace(/.+?st_/, ''))
      this.values = d.values.filter(v => v[1] !== null).map(v => new PKG(this.par, keys, v))
      return this.values
    }
  }

  async to_csv(names, obj, namesL, savename, useCustomTimeFormat = false) {
    return new Promise((resolve, reject) => {
      obj.disabled = true
      try {
        console.log(names, namesL)
        if (names.length == 0) {
          names = namesL || this.keys
        }
        
        // 检查数据量，大数据量时提醒用户
        const dataCount = this.values.length;
        if (dataCount > 10000) {
          if (!confirm(`即将导出 ${dataCount} 条数据，文件较大可能需要一些时间，是否继续？`)) {
            obj.disabled = false;
            resolve();
            return;
          }
        }
        
        // 修改表头格式与页面表格一致，对包含逗号的表头添加双引号转义
        let title = names.map(k => {
          let p = this.par[k];
          let headerText = `${p.id}/${p.n}${p.unit ? (' ' + p.unit) : ''}`;
          // 如果表头包含逗号，用双引号包围，避免CSV分割错误
          return headerText.includes(',') ? `"${headerText}"` : headerText;
        }).join(',')
        let data = [new Uint8Array([0xEF, 0xBB, 0xBF]), `时间,${title}\n`];
        let disp = (v, n) => {
          let dp = v.D(n);
          return (dp === undefined ? 'ERROR' : dp).toString();
        }
        // 定义时间格式化函数
        let timeFormat = useCustomTimeFormat && window._tfmt ? window._tfmt : U2T;
        
        // 分批处理大数据量，避免阻塞UI
        const batchSize = 1000;
        let processedCount = 0;
        
        const processBatch = () => {
          const endIdx = Math.min(processedCount + batchSize, this.values.length);
          for (let i = processedCount; i < endIdx; i++) {
            const v = this.values[i];
            // 修改数据格式与页面表格一致：单列显示"值 [原始值]"
            let line = names.map(n => {
              let displayValue = disp(v, n).replace(/<\/br>/g, ' ');
              let rawValue = v.R(n);
              let unit = v.par[n].Unit || '';
              return `"${displayValue}${unit} [${rawValue}]"`
            }).join(',')
            // 使用自定义时间格式化函数
            let timeStr = useCustomTimeFormat ? timeFormat(new Date(v.time)) : timeFormat(v.time);
            data.push(`${timeStr},${line}\n`)
          }
          processedCount = endIdx;
          
          if (processedCount < this.values.length) {
            // 继续处理下一批
            setTimeout(processBatch, 0);
          } else {
            // 所有数据处理完成，生成文件
            let blob = new Blob(data, {'content_type': 'application/csv;charset=utf8'});
            let a = document.createElement('a');
            a.href = URL.createObjectURL(blob);
            console.log(current_packages);
            a.download = `${savename || current_packages.n}.csv`
            a.click()
            setTimeout(() => {
              URL.revokeObjectURL(a.href)
              obj.disabled = false;
              resolve();
            }, 3000)
          }
        };
        
        // 开始处理
        processBatch();
      } catch (error) {
        obj.disabled = false;
        reject(error);
      }
    });
  }
}
